Spatio-temporal Wikidata. Exploration de données ouvertes et liées du web 3.0
Histoire de cadre : élaboration d’une trajectoire spatio-temporelle
Cette fiche est le fruit d’un dialogue interdisciplinaire entre membres du GT Notebook dans le cadre d’un atelier proposé à la Journée d’études normande sur les données de la recherche qui s’est déroulée en décembre 2021. L’association de plusieurs compétences et disciplines a abouti à ce notebook présentant une analyse exploratoire reproductible de données ouvertes et liées d’un fragment de graphe Wikidata, interrogeables sous la forme de triplets RDF. Les enjeux d’un tel processus inter-disciplinaire sont esquissés en conclusion. L’ébauche des requêtes SPARQL élaborées a fait l’objet d’une présentation et d’échanges au sein des Ateliers du Web Sémantique au printemps 2021.
Introduction
Cette fiche présente une exploration du graphe Wikidata (cf. parties 1.2 et 3) et le traitement des données extraites (cf. parties 2 et 4).
Du requêtage en langage SPARQL (cf. partie 1.3) au traitement et à la représentation des données issues du graphe Wikidata, ce document présente, étape par étape, l’ensemble de la chaîne de traitement réalisée. Le processus exploratoire, parfois itératif, a été conservé afin de mieux comprendre l’approche réflexive des auteurs et autrice. Le notebook retranscrit les démarches scientifique et méthodologique adoptées.
Le schéma organisant ces données est esquissé dans la partie 1. Afin de permettre une reproduction des traitements et des résultats présentés, les données automatiquement collectées au 07 juin 2023 et utilisées dans ce document sont mises à disposition (cf. partie 2.2). L’idée de départ conduit à la démarche suivante en 3 étapes :
- requêter les données (ou suivre des chemins) du graphe
Wikidata,
- identifier certaines des modalités du graphe pouvant comporter une
dimension spatiale et temporelle et ainsi,
- reconstruire et représenter une ou des trajectoires dans le temps et l’espace.
Compte-tenu du formalisme
et de l’hétérogénéïté des données non supervisées de Wikidata, deux
images d’objet (Hui (2015))
sont choisies pour l’étude : un artiste-peintre et une de ses peintures,
exposée au sein de musées ou d’institutions culturelles dans le monde.
Pour reproduire partiellement l’expérimentation, un exemple
d’exploration du graphe Wikidata pour diverses images
d’artistes-peintres est proposée dans la partie 7.
NB : le terme “image”
utilisé dans ce document correspond à une sémantique de l’objet physique
dans l’espace numérique, sous la forme de données et de métadonnées en
relation avec d’autres images d’objet (Hui (2015)).
En ce sens, les oeuvres elles-mêmes, photographiées ou scannées etc.,
sont désignées, sous ces formes (fichiers .jpg .png etc.), par le terme
d’“illustration” ou de fichiers. Pour simplifier le discours, l’image
d’objet est désignée par l’objet lui-même : par exemple, l’image du
peintre Johannes Vermeer, l’entité wikidata de valeur Q41264
définie par ses relations, est identifiée au peintre lui-même.
1 Wikimédia, Wikidata & W3C
1.1 Données ouvertes et liées du graphe Wikidata
Wikidata est une base de connaissances libre, éditée de manière collaborative et hébergée par la fondation Wikimedia. Son contenu étant placé sous licence CC0 (« Transfert dans le Domaine Public »), elle permet de centraliser l’accès aux données utilisées par différents projets Wikimedia (Wikipédia (2021)).
Les informations saisies dans Wikidata sont des données ouvertes “brutes” multilingues non-supervisées qui sont liées, notamment aux articles de l’encyclopédie contributive Wikipedia. Wikidata est à différencier de l’ontologie DBpedia1 (voir figure 1).Source : Wikidata-Basics | Wikidata Hackathon event for the Festival of Creative Learning, 2018
La base Wikidata fournit un support à de nombreux autres sites
et services au-delà des seuls projets de Wikimedia. Son contenu est
exporté dans des formats standards et peut être lié ou aligné à d’autres
ensembles de données ouvertes sur le Web des données2. Wikidata offre ainsi
un large domaine d’informations générales sur notre univers ou ses
représentations et des liens vers d’autres graphes ou bases de données.
Il contient à ce jour plus de 100 millions d’items.
1.2 Standard RDF du W3C
Le RDF est un cadre général de modélisation utilisé pour décrire formellement les ressources du Web via leurs métadonnées afin de permettre le traitement par inférence de telles descriptions. Développé par le W3C, le RDF est le formalisme de base du Web sémantique.
Au sein de ce paradigme, un document ou une ressource consiste en un ensemble de triplets3, chacun associant un sujet, un prédicat et un objet :- le «sujet» représente la ressource à décrire,
- le «prédicat» représente un type de propriété applicable à cette ressource,
- l’«objet» représente une donnée, une autre ressource ou une valeur associée à la propriété (ou prédicat).
Le sujet et l’objet, dans le cas où ce sont des ressources, peuvent être identifiés par un identifiant unique de la ressource (URI4), une valeur ou être des nœuds anonymes. Le prédicat est nécessairement identifié par un URI. Par exemple, la déclaration “Bob s’intéresse à Mona Lisa” est formalisée de la manière suivante :
Plusieurs méthodes permettent d’accéder à ces données. Dans ce notebook, nous utilisons un accès au graphe de Wikidata mobilisant quelques éléments du langage de requête SPARQL, qui n’est pas l’objet de la fiche. L’usage de ce langage de requête spécifique est déployé à l’aide de deux packages :
- le package
wikidataR(et son extensionWikidataQueryServiceR) permet d’écrire la requête dans le langage SPARQL pour le déployer au sein du graphe Wikidata selon ses spécificités, - le package
glitterpermet d’écrire ces requêtes pour sonder divers graphes, dont Wikidata, sans utiliser la syntaxe SPARQL.
1.3 Le langage SPARQL
SPARQL5 (prononcé sparkle, en anglais : « étincelle ») est à la fois un langage de requête et un protocole qui permettent de rechercher, d’ajouter, de modifier ou de supprimer des triplets RDF disponibles à travers le Web. Aujourd’hui, le Web de données (représenté par le nuage du Linked Open Data ou ses domaines) est interrogeable via des centaines de services SPARQL qui mettent à disposition de plus en plus de graphes de données ouvertes et liées comme c’est le cas du projet plurilingue Wikidata (Wikipédia (2022)).
Dans ce notebook, quelques requêtes de base permettant d’interroger la base de données Wikidata utilisent les éléments suivants :
- la clause
SELECTdes données interrogées qui renvoit les variables spécifiques (ou avecCOUNTle nombre des ces données, regroupées parGROUP BYet triées parORDER BY),
- accompagnée de la clause
WHERE { }qui les lie à l’interrogation de propriétés et données associées, sur les chemins du graphe,
- un service WikiLabel spécifique au point d’accès Wikidata Query
Service, du fait du caractère plurilingue des données du graphe
Wikidata, permettant de choisir la langue du label
(
wikibase:language) associé à l’entité ou la propriété recherchée,
- la fonctionnalité
OPTIONALde la clauseWHEREqui permet de renvoyer les variables même si les données liées aux propriétés ne sont pas instanciées (noeuds vides),
- et les différents préfixes associés aux spécificités des propriétés
directes et indirectes des fragments de graphe de Wikidata (+d’info).
Afin de permettre une bonne compréhension des requêtes réalisées pour la collecte de données sans entrer dans la syntaxe propre à SPARQL, celles-ci sous formulées de la manière suivante (les éléments en italique ne sont pas nécessaires) :
SELECT données interrogées,
comptage WHERE { chemins principaux du
graphe, service Wikilabel, chemins optionnels ou
secondaires du graphe } groupe et ordonne
2 Packages et données
2.1 Packages utilisés
Les packages utilisés pour réaliser l’ensemble de la chaîne
de traitement présenté dans ce document sont les suivants : -
WikidataR et WikidataQueryServiceR:
fournissent une Interface de Programmation d’Application (API) pour le
service
de requêtes Wikidata;
- glitter : écrit et envoie des requêtes SPARQL sans en
connaître la syntaxe;
- rnaturalearth : met à disposition les données
géographiques de Natural Earth;
- sf : permet la gestion et la manipulation de données
géographiques;
- dplyr : facilite la manipulation de données;
- mapview : produit des cartes interactives en utilisant la
librairie JavaScript Leaflet;
- tmap : produit de cartes thématiques;
- ggplot2 : permet la production de graphiques basés sur la
grammaire
graphique;
- av : génère des vidéos à partir d’images ou de graphiques
R;
- patchwork : combine facilement plusieurs graphiques
ggplot2;
- jpeg : importe, enregistre et affiche des images
matricielles (format bitmap);
- DT : met en forme dynamique (HTML) des tableaux de
données (bibliothèque javascript DataTables).
Vous pouvez utiliser les lignes de code suivantes pour installer ces packages : elles permettent de n’installer que les packages nécéssaires qui ne sont pas déjà installés sur votre machine :
# Liste des packages du CRAN nécessaires
liste_packages <- c("WikidataR",
"WikidataQueryServiceR",
"remotes",
"rnaturalearth",
"sf",
"dplyr",
"mapview",
"tmap",
"ggplot2",
"av",
"patchwork",
"jpeg",
"DT")
# Packages à installer
liste_packages_a_installer <- liste_packages[!(liste_packages %in% installed.packages()[,"Package"])]
# Installation des packages manquants
install.packages(liste_packages_a_installer)# Pour installer le *package* `glitter` sur GitHub (https://github.com/lvaudor/glitter/), mettre l'option eval = TRUE :
install.packages("remotes")
remotes::install_github("lvaudor/glitter")2.2 Données collectées
Plusieurs sources de données sont utilisées pour ce travail exploratoire :
- des données issues du graphe Wikidata,
- une couche géographique Natural Earth,
- et un fonds de carte mis à disposition par Leaflet.
3 Exploration du graphe Wikidata
Le service de collecte des
données de Wikidata en langage SPARQL offre une solution très
complète en première approche (exemples, assistant de requêtes,
diversité des représentations etc.). Toutefois, dans une dynamique
d’exploration du graphe Wikidata, l’utilisation de R facilite la
compréhension, l’archivage et la reproductibilité des différentes
requêtes spécifiques réalisées. Pour cette raison, nous utilisons le
package WikidataR
ou alternativement WikidataQueryServiceR
qui est un package ayant des fonctionnalités plus développées, ainsi que
la version en développement de glitter.
WikidataR
est développé par Thomas Shafee, Os Keyes, Serena Signorelli, Alex Lum,
Christian Graul et Mikhail Popov (développeur de
WikidataQueryServiceR), membre de la Fondation Wikimédia.
Il est maintenu par Thomas Shafee de l’université australienne La Trobe
de l’état Victoria. glitterest développé notamment par Lise
Vaudor, ingénieure de recherche à l’ENS Lyon.
3.1 Modèle des données : artistes-peintres et trajectoires de leurs œuvres
Dans Wikidata, les peintres, peintures, collections et lieux d’exposition, et leurs coordonnées spatiales et temporelles sont modélisés selon les fragments de graphes (XML, json, turtle etc.) représentés ci-dessous (Figures 4 et 6). Ceux-ci comprennent des classes instanciées liées entre elles par des propriétés (prédicats) mobilisant une syntaxe spécifique associée à chaque espace de nom, les préfixes6.
Le fragment de graphe de l’image Wikidata d’une peinture, objet du processus exploratoire, est illustré sous la forme d’un tableau en figure 6b. Pour plus d’informations, vous pouvez consulter l’introduction à Wikidata ou la page Wikibase dédiée au formalisme du Ressource Description Framework (RDF) du dépôt de données Wikidata.
Après plusieurs explorations, nous avons décidé de nous intéresser,
dans une première étape, au peintre néerlandais du 17e siècle,
Johannes Vermeer. Au sein du package
WikidataR, une fonction simple permet d’interroger le
graphe à partir d’une chaîne de caractère. Par exemple, il est possible
de collecter les entités (item) correspondant à la chaîne de
caractère “Johannes Vermeer” ou les propriétés (properties)
associées à celle de “peintre” :
#---
# Package API du CRAN pour interroger le dépôt Wikidata : WikidataR
library(WikidataR)
## Chercher les entités du graphe Wikidata correspondant à "Johannes Vermeer"
find_item("Johannes Vermeer")
Wikidata item search
Number of results: 10
Results:
1 Johannes Vermeer (Q41264) - Dutch painter (1632–1675)
2 Jan Vermeer van Haarlem the Elder (Q3159680) - painter from the Northern Netherlands and father of Barend, Isaac, and Jan Vermeer or van der Meer II (1628-1691)
3 Johannes Vermeer (Q15283995) - art exhibition
4 Johannes Vermeer (Q102229722) - Ph.D. Vrije Universiteit Amsterdam 1983
5 Johannes Vermeer (Q2164464) - international train between Amsterdam and Cologne
6 Johannes Vermeer (Q19280548) - street in Ouderkerk aan de Amstel, the Netherlands
7 Johannes Vermeer catalog raisonné, 1908 (Q26235177) - catalog raisonné of Vermeer works by Cornelis Hofstede de Groot
8 Johannes Vermeer Award (Q2141982) - Dutch art award
9 Johannes Vermeerstraat (Q1951387) - street in Amsterdam
10 Jan Vermeer van Haarlem (ca.1600-1670) (Q28736462) - Dutch art dealer, distiller, and possibly landscapist, ca. 1600-1670, father and grandfather of well-known painters
## Chercher les propriétés du graphes correspondant à "peintre"
find_property("peintre")
Wikidata property search
Number of results: 1
Results:
1 creator (P170) - maker of this creative work or other object (where no more specific property exists)
Une seule entité (Q41264) du graphe parmi les dix
collectées semble correspondre à l’image (au sens de (Hui 2015)) de Johannes Vermeer, le
peintre recherché. La propriété correspondant au peintre
(P170) semble être celle, générique, liant un créateur à
son oeuvre ou autre objet. Afin de poursuivre l’investigation du graphe
et permettre de collecter de manière précise des données
spatio-temporelles associées aux “oeuvres créées par Johannes Vermeer”,
les modalités d’interrogation du fragment de graphe se
complexifient.
3.2 Trouver l’identifiant Wikidata d’un peintre
Nous interrogeons le graphe Wikidata concernant le peintre Johannes Vermeer, instance de Wikidata (classe d’objet P31), qui est un humain (Q5) répondant à la catégorie commune (P373) “Johannes Vermeer” selon le schéma simplifié proposé dans la figure 4.
SELECT
s’applique aux éléments figurés en données en sortie. Les propriétés et
objets associés (en entrée ou sortie), c’est-à-dire les chemins du
graphe, sont insérés dans l’accollade de WHERE.
A l’aide de la fonction query_wikidata du package
WikidataR ou alternativement des fonctions du package
glitter, nous commençons dans un premier temps par obtenir
l’illustration associée à Johannes Vermeer (renseignée par la propriété
P18),
avec la requête SPARQL suivante :
#---
# Package API du CRAN pour interroger le dépôt Wikidata : WikidataR
library(WikidataR)
## Chercher les entités du graphe Wikidata
#- Données wikidata
id_wikidata <- paste("?identifiant")
donnee_image <- paste("?image")
#- Préfixe entité utilisé
prefixe_entite <- paste("wd:")
#- un humain (Q5)
entite_humaine <- paste0(prefixe_entite,"Q5")
donnees_interrogees <- paste(id_wikidata,donnee_image)
## Construire les chemins du graphe
#- Définir les propriétés utilisées
propriete_type <- paste("P31")
propriete_categorie <- paste("P373")
propriete_image <- paste("P18")
#- Préfixe propriété utilisé
prefixe_propriete_simple <- paste("wdt:")
#- Définir le type de prédicat utilisé
predicat_type <- paste0(prefixe_propriete_simple,propriete_type)
predicat_categorie <- paste0(prefixe_propriete_simple,propriete_categorie)
predicat_image <- paste0(prefixe_propriete_simple,propriete_image)
#- Chemins du graphe
chemin_principal <- paste(id_wikidata,predicat_type,entite_humaine)
chemin_categorie <- paste(id_wikidata,predicat_categorie,"'Johannes Vermeer'")
chemin_image <- paste(id_wikidata,predicat_image,donnee_image)
chemins_du_graphe <- paste(chemin_principal,".",chemin_categorie,".",chemin_image)
## Construire la requête
query <- paste("SELECT",donnees_interrogees,"WHERE {",chemins_du_graphe,"}")
## Exécuter la requête
data1w <- query_wikidata(query)
#---
# Package API en développement pour interroger un dépôt RDF sans connaître la syntaxe SPARQL : glitter
library(glitter)
## Initier la requête et stocker le résultat dans data1
data1 <- spq_init() |>
## Ajouter les chemins du graphe
spq_add("?identifiant wdt:P31 wd:Q5") |>
spq_add(". wdt:P373 'Johannes Vermeer'") |>
spq_add(". wdt:P18 ?image") |>
## Executer la requête
spq_perform()Les données collectées des deux manières distinctes sont affichées :
# Affichage dynamique des tables issues des deux manières d'interroger le graphe
library(DT)
#--- avec WikidataR
datatable(data1w)#--- avec glitteR
datatable(data1)et la valeur associée à l’image d’objet étudiée, Johannes Vermeer,
est affectée à une variable id_vermeer :
# Affectation à la variable 'id_vermeer' de la valeur de l'identifiant wikidata
dataid <- strsplit(data1$identifiant,"/")
id_vermeer <- dataid[[1]][5]
id_vermeer[1] "Q41264"
Le résultat renvoyé par cette requête nous permet de vérifier que
l’image de l’objet Johannes Vermeer est bien identifiée par une
entité Q41264
dans Wikidata et/ou son URI. Le fichier associé à la
peinture de son portrait est stocké en deux étapes (création de
répertoire, téléchargement), à partir de son URI collectée avec le
package glitter :
# Création des sous-répertoires 'data' et 'data/image'
dir.create("data")
dir.create("data/images")# Téléchargement et sauvegarde du fichier de l'image numérisée
download.file(url = data1$image,
destfile = 'data/images/portrait_artiste.jpg',
mode = 'wb')
Dans ce qui suit, l’identifiant trouvé permet de déterminer les images
(au sens de (Hui 2015)) des œuvres de Johannes
Vermeer par la propriété (P170 est créé par).
3.3 Lister les œuvres du peintre et trouver leurs localisations géographiques
Dans cette seconde étape, on se propose de lister les œuvres de
Johannes Vermeer avec leurs localisations. Au sein du graphe Wikidata,
les coordonnées de la localisation (valeur point(x,y))
d’une oeuvre sont attachées au musée ou l’institution au sein de
laquelle l’oeuvre est actuellement exposée ou située. Afin d’obtenir
cette localisation à partir de l’identifiant du peintre, on trace un
premier chemin du graphe tel qu’illustré dans la figure 6a.
Q...) est créée par (P170)
l’entité Johannes Vermeer (id_vermeer) et a pour lieu (P276)
l’entité musée (Q...) qui a pour coordonnées (P625)
la valeur point(x,y), coordonnées géographiques du système
de référence World Geodetic System (WGS84).
Le nom des oeuvres et des musées (suffixe Label”) est obtenu par le
service wikibase:label du package
WikidataQueryServiceR dans la langue
wikibase:language choisie.
#--- avec WikidataR
library(WikidataR)
## Chercher les entités du graphe Wikidata
#- Données wikidata
id_oeuvre <- paste("?oeuvre")
id_lieu <- paste("?musee")
val_pointxy <- paste("?coord")
#- Entité Vermeer le peintre
entite_vermeer <- paste0(prefixe_entite,id_vermeer)
donnees_interrogees <- paste(id_oeuvre,id_lieu,val_pointxy)
## Construire les chemins du graphe pour les entités
#- Définir les propriétés utilisées
propriete_creepar <- paste("P170")
propriete_lieu <- paste("P276")
propriete_coord <- paste("P625")
#- Définir le type de prédicat utilisé
predicat_creepar <- paste0(prefixe_propriete_simple,propriete_creepar)
predicat_lieu <- paste0(prefixe_propriete_simple,propriete_lieu)
predicat_coord <- paste0(prefixe_propriete_simple,propriete_coord)
#- Chemins du graphe
chemin_principal <- paste(id_oeuvre,predicat_creepar,entite_vermeer)
chemin_lieu <- paste(id_oeuvre,predicat_lieu,id_lieu)
chemin_coord <- paste(id_lieu,predicat_coord,val_pointxy)
chemins_du_graphe <- paste(chemin_principal,".","OPTIONAL {",chemin_lieu,".",chemin_coord,"}")
## Construire la requête
query <- paste("SELECT",donnees_interrogees,"WHERE {",chemins_du_graphe,"}")
## Exécuter la requête
data2w <- query_wikidata(query)
#--- avec WikidataQueryService
library(WikidataQueryServiceR)
## Utiliser le service Wikidata de noms (`wikibase:label`) plurilingues des entités de Wikidata
#- définir la ou les langues choisies
langue <-"fr,en"
#- définir les prédicats associés
prefixe_wikibase <- paste0("wikibase:")
propriete_label <- paste0("label")
propriete_langue <- paste0("language")
predicat_label <- paste0(prefixe_wikibase,propriete_label)
predicat_langue <- paste0(prefixe_wikibase,propriete_langue)
service <- paste("SERVICE",predicat_label,"{ bd:serviceParam",predicat_langue,"\"[AUTO_LANGUAGE],",langue,"\".}")
## Chercher les noms en français des entités recherchées du graphe Wikidata
#- Nom (ou label) des données wikidata
nom_id_oeuvre <- paste0(id_oeuvre,"Label")
nom_id_lieu <- paste0(id_lieu,"Label")
nom_donnees_interrogees <- paste(nom_id_oeuvre,nom_id_lieu,val_pointxy)
## Construire la requête avec le service de langue
query_label <- paste("SELECT",nom_donnees_interrogees,"WHERE {",service,chemins_du_graphe,"}")
## Exécuter la requête
data2wl <- query_wikidata(query_label)
#---avec glitter
library(glitter)
## Initier la requête et stocker le résultat dans data2
data2 <- spq_init() |>
## Ajouter les chemins du graphe
#- chemin principal
spq_add("?oeuvre wdt:P170 wd:Q41264", .label="?oeuvre") |>
#- chemins optionnels
spq_add("?oeuvre wdt:P276 ?musee", .label="?musee", .required=FALSE) |>
spq_add("?musee wdt:P625 ?coord", .required=FALSE) |>
## Sélectionner les données interrogées
spq_select(-oeuvre,-loc,-musee) |>
## Exécuter la requête
spq_perform()Les données collectées par les diverses techniques présentées sont
affichées en utilisant la fonction datatable de la library
DT:
library(DT)
#---WikidataR
datatable(data2w)#---WikidataQueryService
datatable(data2wl)#---glitter
datatable(data2)3.4 Premiers éléments d’analyse exploratoire
3.4.1 Quelques constats sur le graphe et les données
On constate que les données (non supervisées) du graphe Wikidata concernant les lieux d’exposition des œuvres de Vermeer et leurs coordonnées géographiques sont hétérogènes :
- certaines œuvres semblent n’avoir aucune localisation, l’information n’étant pas disponible dans le graphe Wikidata tel qu’interrogé (voir ci-dessous),
- d’autres semblent être liées à des lieux correspondant à des données d’une autre nature qu’un musée ou institution (par exemple, Leiden Collection pour l’oeuvre “A Young Woman Seated at the Virginals” ou encore Room 837 (une salle du musée du Louvre) pour “The Lacemaker” etc.), sans coordonnées géographiques associées,
- enfin, parmi les œuvres localisées (voir tables supra), certaines présentent plusieurs localisations de nature différente (par exemple, l’oeuvre “The Astronomer”), et dans certains cas, plusieurs fois le même musée avec éventuellement des coordonnées très légèrement distinctes (par exemple, “The Geographer” au Städel Museum) etc.
library(DT)
datatable(tail(data2wl))datatable(tail(data2))Pourquoi ? Plusieurs hypothèses peuvent être esquissées :
un même musée peut avoir plusieurs coordonnées géographiques renseignées (plusieurs couples du
Point(x,y)très proches, par exemple pour le Städel Museum),la localisation d’une œuvre peut conduire à une entité qui n’est ni un musée ni une institution culturelle mais le nom d’une collection (par exemple The Leiden Collection) ou d’une salle (par exemple Room 837 qui est une salle du musée du Louvre) etc.,
une même œuvre peut être située dans plusieurs musées (ou plusieurs fois dans un même musée), peut-être à des périodes différentes.
Ces constats sont liés non seulement au caractère non supervisé et collectif (hétérogène, voire lacunaire) de la production des données, mais aussi à la complexité de la saisie des données dans le graphe Wikidata. En conséquence, les modalités d’interrogation du graphe Wikidata sont multiples, en fonction notamment de la profondeur du graphe qui est sondée et de la qualité de l’affectation de valeurs à ses instances.
La série de requêtes présentées jusqu’à présent interroge les entités
Wikidata renseignées au moyen des propriétés simples de localisation,
avec le préfixe wdt. Pour aller plus en profondeur dans le
graphe, vérifier la localisation et déterminer sa composante temporelle,
il est nécessaire d’entrer plus en détail dans une autre forme
d’instanciation du graphe, spécifique à Wikidata, à savoir les
déclarations (voir figure 6b).
P276 a pour lieu). Le lien entre l’œuvre et son
créateur est aussi une déclaration, objet de la propriété
(P170 est créé par), mais ne comporte pas de valeur
spatiale ou temporelle. Source : Wikidata
3.4.2 Préciser les chemins du graphe de données associé au peintre
Cette représentation tabulaire du graphe permet de comprendre que les
modalités d’accès aux données peuvent prendre d’autres chemins du graphe
que celui ‘de premier niveau’ des relations entre entités et propriétés
directes (préfixe wdt). Dans un premier temps, afin de
mieux cerner la profondeur du graphe Wikidata, il est possible de
l’interroger pour connaître toutes les relations (arêtes du graphe)
associées à l’objet Johannes Vermeer conduisant à au moins une instance
du graphe*. L’image d’objet id_vermeer peut alors prendre
la position de “sujet” des prédicats et objets recherchés ou celle
d’“objet” des prédicats et sujets (voir figure 6c).
*on exclut ici les noeuds vides.
3.4.2.1 Sonder le graphe pour toute propriété et son nombre d’ objets concernant le peintre comme sujet du prédicat
library(WikidataQueryServiceR)
library(DT)
## Chercher les noms propriétés du graphe Wikidata et le nombre d'objets associés
#- objets des propriétés recherchées, liées au peintre
id_objet <- paste("?objet")
#- compteur et comptage de ces objets associés aux propriétés interrogées
compteur <- paste("?count")
comptage <- paste0("(COUNT(DISTINCT",id_objet,") AS ",compteur,")")
ordre_decroissant <- paste0("ORDER BY DESC(",compteur,")")
#- propriétés ?propriete - de différents types, attachées au peintre
id_propriete <- paste("?propriete")
id_propriete_simple <- paste0(id_propriete,"_simple")
id_propriete_directe <- paste0(id_propriete,"_directe")
#- nom de ces types de propriétés
nom_id_propriete_simple <- paste0(id_propriete_simple,"Label")
nom_id_propriete_directe <- paste0(id_propriete_directe,"Label")
nom_proprietes_objets_interrogees <- paste(id_propriete,nom_id_propriete_simple,nom_id_propriete_directe)
## Construire les chemins du graphe pour les propriétés de différents types (et entités associées)
#- chercher les propriétés et objets du sujet Vermeer
chemin_primaire <- paste(entite_vermeer,id_propriete,id_objet)
#- dont les types wikidata de prédicats sont simples ou directs
prefixe_wikibase <- paste0("wikibase:")
type_predicat_simple <- paste0(prefixe_wikibase,"claim")
type_predicat_direct <- paste0(prefixe_wikibase,"directClaim")
chemin_type_predicat_simple <- paste(id_propriete_simple,type_predicat_simple,id_propriete)
chemin_type_predicat_directe <- paste(id_propriete_directe,type_predicat_direct,id_propriete)
chemins_du_graphe <- paste(chemin_primaire,".","OPTIONAL {",chemin_type_predicat_directe,"}","OPTIONAL {",chemin_type_predicat_simple,"}")
## Grouper et ordonner
groupe_et_ordonne <- paste("GROUP BY",nom_proprietes_objets_interrogees,ordre_decroissant)
## Construire la requête
query <- paste("SELECT",nom_proprietes_objets_interrogees,comptage,"WHERE {",service,chemins_du_graphe,"}",groupe_et_ordonne)
## Exécuter la requête
metadonnees_relations_comme_sujet <- query_wikidata(query)
## Afficher le résultat
datatable(metadonnees_relations_comme_sujet)3.4.2.2 Sonder le graphe pour toute propriété et son nombre de sujets concernant le peintre comme objet du prédicat
library(WikidataQueryServiceR)
library(DT)
## Chercher les noms propriétés du graphe Wikidata et le nombre de sujets associés
#- sujets des propriétés recherchées, dont le peintre est l'objet
id_sujet <- paste("?sujet")
#- compteur et comptage de ces sujets associés aux propriétés interrogées
comptage <- paste0("(COUNT(DISTINCT",id_sujet,") AS ",compteur,")")
ordre_decroissant <- paste0("ORDER BY DESC(",compteur,")")
#- propriétés ?propriete - de différents types, attachées au peintre
id_propriete_declarative <- paste0(id_propriete,"_declarative")
id_propriete_qualificative <- paste0(id_propriete,"_qualificative")
#- nom de ces types de propriétés
nom_id_propriete_declarative <- paste0(id_propriete_declarative,"Label")
nom_id_propriete_qualificative <- paste0(id_propriete_qualificative,"Label")
nom_proprietes_sujets_interrogees <- paste(id_propriete,nom_id_propriete_directe,nom_id_propriete_qualificative,nom_id_propriete_declarative)
## Construire les chemins du graphe pour les propriétés de différents types (et entités associées)
#- chercher les propriétés et sujets de l'objet Vermeer
chemin_primaire <- paste(id_sujet,id_propriete,entite_vermeer)
#- dont les types wikidata de prédicats sont simples ou directs
prefixe_wikibase <- paste0("wikibase:")
type_predicat_declaration <- paste0(prefixe_wikibase,"statementProperty")
type_predicat_qualificatif <- paste0(prefixe_wikibase,"qualifier")
chemin_type_predicat_declaration <- paste(id_propriete_declarative,type_predicat_declaration,id_propriete)
chemin_type_predicat_qualificatif <- paste(id_propriete_qualificative,type_predicat_qualificatif,id_propriete)
chemins_du_graphe <- paste(chemin_primaire,".","OPTIONAL {",chemin_type_predicat_directe,"}","OPTIONAL {",chemin_type_predicat_declaration,"}","OPTIONAL {",chemin_type_predicat_qualificatif,"}")
## Grouper et ordonner
groupe_et_ordonne <- paste("GROUP BY",nom_proprietes_sujets_interrogees,ordre_decroissant)
## Construire la requête
query <- paste("SELECT",nom_proprietes_sujets_interrogees,comptage,"WHERE {",service,chemins_du_graphe,"}",groupe_et_ordonne)
## Exécuter la requête
metadonnees_relations_comme_objet <- query_wikidata(query)
## Afficher le résultat
datatable(metadonnees_relations_comme_objet)Parmi l’ensemble des propriétés qui sont les relations du peintre Johannes Vermeer aux autres objets ou sujets dans le graphe Wikidata, on s’intéresse particulièrement
- à la propriété (
P170 créé par) qui l’associe à ses œuvres (dont Vermeer est l’“objet”), - et à
(
P6379 collection comprenant une œuvre de la personne), qui l’associe aux collections qui contiennent ses œuvres, (dont Vermeer est le “sujet”).
3.4.3 Le corpus des
œuvres de (P170) Johannes Vermeer selon Wikidata
En sondant les propriétés dont Vermeer est l’objet, le résultat du
3.4.2.2 renvoit au moins 2 nombres pour la propriété
P170 créé par :
- dans le premier cas
prop/statement/P170correspondant aux déclarations exhaustives, le graphe compte 43 oeuvres, - dans le second cas
prop/direct/P170correspondant aux relations simples (ou “quasi-vérités”), on compte 37 oeuvres, soit un écart de 6 oeuvres.
En différenciant les modalités d’interrogation associées aux
prédicats (préfixes p:, ps: et
wdt:), il est possible de connaître la liste de ces oeuvres
objets d’une déclaration exhaustive au sein du fragment de graphe
wikidata qui ne sont pas des “quasi-vérités” :
library(WikidataQueryServiceR)
library(DT)
library(dplyr)
## Entités ou déclarations wikidata interrogées
donnees_interrogees <- paste(id_oeuvre,nom_id_oeuvre)
## Construire les chemins du graphe
#- Définir le type de prédicat utilisé pour une entité déclarative ?obj a wikibase:statement
prefixe_propriete_directe <- paste0("p:")
prefixe_propriete_declarative <- paste0("ps:")
predicat_creepar_direct <- paste0(prefixe_propriete_directe,propriete_creepar)
predicat_creepar_declaratif <- paste0(prefixe_propriete_declarative,propriete_creepar)
predicat_creepar_declaration <- paste0(predicat_creepar_direct,"/",predicat_creepar_declaratif)
#- Suivre les deux chemins du graphe
chemin_declaration <- paste(id_oeuvre,predicat_creepar_declaration,entite_vermeer)
chemin_simple <- paste(id_oeuvre,predicat_creepar,entite_vermeer)
## Ordonner
ordonne <- paste("ORDER BY DESC(",id_oeuvre,")")
## Construire les requêtes
query_declaration <- paste("SELECT",donnees_interrogees,"WHERE {",service,chemin_declaration," }",ordonne)
query_valeur_simple <- paste("SELECT ",donnees_interrogees,"WHERE {",service,chemin_simple," }",ordonne)
## Stocker le résultat de l'exécution des requêtes
resultats_oeuvres_exhaustif <- query_wikidata(query_declaration)
resultats_oeuvres_valeur_simple <- query_wikidata(query_valeur_simple)
## Comparaison et affichage des oeuvres présentes seulement dans les déclarations exhaustives associées à la propriété
oeuvres_declarees=resultats_oeuvres_exhaustif %>% filter(!oeuvre %in% resultats_oeuvres_valeur_simple$oeuvre)
datatable(oeuvres_declarees)Pour connaître la nature de la relation de ces oeuvres au peintre Johannes Vermeer, il est possible de sonder le fragment de graphe plus en profondeur (voir figure 6d), notamment au moyen :
- de prédicats de qualification des déclarations (dits
qualifiers avec le préfixe
pq:), trouvés au sein des résultats du 3.4.2.2, à savoir par exemple :P1777 à la manière de,P1778 faux imitant,P1778 d'après une oeuvre de,P1774 atelier deetP1775 suiveur deJohannes Vermeer, - mais aussi d’autres éléments du graphe Wikidata permettent par
ailleurs de préciser le corpus d’oeuvres créées par Johannes Vermeer,
comme par exemple le rang (
wikibase:rank) associé à la déclaration d’attribution (ps:) de l’oeuvre ou à la qualification (pq:) de cette attribution.
wdt) et les relations au sein des déclarations au moyen des
propriétés indirectes (préfixes p, ps ou
pq) utilisées supra. Source : Wikibase
Pour avoir une vue d’ensemble sur le corpus des oeuvres attribuées à Johannes Vermeer, on regroupe les deux types de prédicats associés aux relations entre le peintre et les oeuvres.
library(WikidataQueryServiceR)
library(DT)
library(dplyr)
## Chercher les entités, leur nom (qui sera filtré par la langue choisie) et leur rang
#- Rang wikidata et déclarations
val_rang <- paste("?rang")
declaration <- paste("?objet_declaratif")
donnees_interrogees <- paste(id_oeuvre,nom_id_oeuvre,val_rang)
## Construire les chemins du graphe
#- prédicats utilisés
prefixe_rdfs <- paste0("rdfs:")
propriete_rang <- paste0("rank")
predicat_rang <- paste0(prefixe_wikibase,propriete_rang)
predicat_rdfs_label <- paste0(prefixe_rdfs,propriete_label)
#- chemins du graphe
chemin_declaratif <- paste(declaration,predicat_creepar_declaratif,entite_vermeer)
chemin_rang_declaration <- paste(declaration,predicat_rang,val_rang)
chemin_direct <- paste(id_oeuvre,predicat_creepar_direct,declaration)
chemin_rdfs_label <- paste(id_oeuvre,predicat_rdfs_label,nom_id_oeuvre)
chemins_du_graphe <- paste(chemin_declaratif,".",chemin_rang_declaration,".","OPTIONAL {",chemin_direct,".",chemin_rdfs_label,"}")
## Requête
#- Filtre de langue des noms
filtre_langue <- paste0("FILTER(lang(",nom_id_oeuvre,")=\"en\")")
query <- paste("SELECT",donnees_interrogees,"WHERE {",chemins_du_graphe,filtre_langue," }")
## Affectation du résultat
resultats_oeuvres <- query_wikidata(query)
## Chercher le prédicat qualificatif et son rang associé
donnees_interrogees <- paste(id_oeuvre,nom_id_oeuvre,nom_id_propriete_qualificative,val_rang)
## Chemins du graphe
chemin_declaration <- paste(declaration,id_propriete,entite_vermeer)
chemin_rang_qualification <- paste(declaration,predicat_rang,val_rang)
chemin_qualificatif <- paste(id_propriete_qualificative,type_predicat_qualificatif,id_propriete)
chemins_du_graphe <- paste(chemin_declaration,".",chemin_rang_qualification,".",chemin_qualificatif,".",chemin_direct,".",chemin_rdfs_label)
## Requête
query <- paste("SELECT ",donnees_interrogees,"WHERE {",chemins_du_graphe,filtre_langue,service," }",ordonne)
## Affectation du résultat
resultats_relations <- query_wikidata(query)
## Jointure de toutes les oeuvres liées directement ou indirectement à Johannes Vermeer
resultats_total=full_join(resultats_oeuvres,resultats_relations,by="oeuvre")
nombre <- count(resultats_total)
nombre# A tibble: 1 × 1
n
<int>
1 58
## Sélection de celle dont l'attribution comme peintre est de rang dépréciée
resultats_deprecated=filter(resultats_total, rang.x == "http://wikiba.se/ontology#DeprecatedRank")
datatable(resultats_deprecated)## Sélection de celle dont la qualification correspond à une oeuvre non réalisée par Johannes Vermeer
resultats_qualified=filter(resultats_total, propriete_qualificativeLabel != "NULL")
datatable(resultats_qualified)On esquisse ici l’approche qui, interrogeant le fragment de graphe
Wikidata de manière plus approfondie, permet d’analyser la qualité des
données issues des interrogations simplifiées ou “quasi-vérités” (voir
figure 6d.) mais aussi d’appréhender la complexité de la modélisation
conceptuelle d’une oeuvre à travers sa genèse et le discours associé. Il
semble que l’écart entre les “quasi-vérités” (avec le préfixe
wdt:) et les déclarations exhaustives (avec le préfixe
ps:) de la relation de Johannes Vermeer à se oeuvres
s’explique par le rang de celles-ci. En complément, on note que :
- en tout 58 oeuvres sont liées à Vermeer comme créateur,
- 20 d’entre elles semblent ne pas être “de sa main”,
- 4 sont qualifiées ainsi du point de vue de l’histoire de l’art parmi les 6 oeuvres “dépréciées”,
- et celle identifiée par
Q20810246, appelée Lady with a Guitar comporte un rang normal (non déprécié) avec la qualification d’appartenance à l’atelier de.
Ce dernier point permet d’introduire les modalités définies au sein du graphe wikidata pour une telle incertitude d’attribution de l’oeuvre au peintre Johannes Vermeer. Il s’agit des références citées dans la déclaration qui définissent la provenance de l’assertion.
library(WikidataQueryServiceR)
library(DT)
library(dplyr)
## Chercher les entités citée en référence des déclarations sur l'oeuvre étudiée
#- Données wikidata
donnee_url <- paste("?url")
id_reference <- paste("?reference")
qid_oeuvre <- paste("Q20810246")
entite_oeuvre <-paste0(prefixe_entite,qid_oeuvre)
donnees_interrogees <- paste(donnee_url)
## Construire les chemins du graphe
#- Définir la propriété de la relation de la déclaration à sa référence & url
propriete_ref <- paste("wasDerivedFrom")
propriete_url <- paste("P854")
#- Définir le type de prédicat utilisé
prefixe_provenance <- paste0("prov:")
prefixe_reference_url <- paste0("pr:")
predicat_provenance <- paste0(prefixe_provenance,propriete_ref)
predicat_url <- paste0(prefixe_reference_url,propriete_url)
#- Chemins du graphe
chemin_principal <- paste(entite_oeuvre,predicat_creepar_direct,declaration)
chemin_provenance <- paste(declaration,predicat_provenance,id_reference)
chemin_url <- paste(id_reference,predicat_url,donnee_url)
## Requête
query <- paste("SELECT",donnees_interrogees,"WHERE {",chemin_principal,".",chemin_provenance," . ",chemin_url," }")
## Affectation & affichage du résultat et des sources citées dans wikidata
resultats_sources <- query_wikidata(query)
datatable(resultats_sources)## Intégration des sources dans le notebook pour lecture immédiate
knitr::include_url(resultats_sources$url[[1]])knitr::include_url(resultats_sources$url[[2]])La seconde analyse porte sur la notion de collection d’une oeuvre et des modalités pratiques de son instanciation au sein du graphe Wikidata.
3.4.4 Les collections associées aux oeuvres de Johannes Vermeer
De même, il est possible d’identifier la qualité des informations
associées aux collections auxquelles les oeuvres de Vermeer sont
attribuées, notamment en qualifiant le type P31 d’instance,
objet du prédicat P6379.
library(WikidataQueryServiceR)
library(DT)
## Chercher les instances des collections du graphe Wikidata qui contiennent une oeuvre de Vermeer
#- objets (et type de ceux-ci) de la propriété recherchée "est collection", dont l'oeuvre du peintre est membre
id_objet <- paste("?objet")
type_id_objet <- paste("?type_objet")
#- compteur et comptage de ces sujets associés aux propriétés interrogées
comptage <- paste0("(COUNT(DISTINCT",id_objet,") AS ",compteur,")")
ordre_decroissant <- paste0("ORDER BY DESC(",compteur,")")
#- propriétés utilisées
id_propriete <- paste0("P6379")
#- nom du types des objets "collection"
nom_type_id_objet <- paste0(type_id_objet,"Label")
## Construire les chemins du graphe pour les propriétés de différents types (et entités associées)
#- prédicats utilisés
predicat_collection_direct <- paste0(prefixe_propriete_directe,id_propriete)
predicat_collection_declaratif <- paste0(prefixe_propriete_declarative,id_propriete)
predicat_collection_declaration <- paste0(predicat_collection_direct,"/",predicat_collection_declaratif)
#- chercher les objets collections contenant des oeuvres de Vermeer
chemin_primaire <- paste(entite_vermeer,predicat_collection_declaration,id_objet)
chemin_type <- paste(id_objet,predicat_type,type_id_objet)
chemins_du_graphe <- paste(chemin_primaire,".",chemin_type)
## Grouper et ordonner
groupe_et_ordonne <- paste("GROUP BY",nom_type_id_objet,ordre_decroissant)
## Construire la requête
query <- paste("SELECT",nom_type_id_objet,comptage,"WHERE {",service,chemins_du_graphe,"}",groupe_et_ordonne)
## Exécuter la requête
metadonnees_collections_comme_objet <- query_wikidata(query)
## Afficher le résultat
datatable(metadonnees_collections_comme_objet)Les modalités d’instanciation de ces assertions semblent hétérogènes
au sein de Wikidata : en effet, on compte 15 types différents dont
seulement 2 se réfèrent au terme collection, la majorité étant de type
musée d'art.
Afin de cerner à quel type d’instance la propriété associant les oeuvres
à des collections fait référence, il est possible d’ajouter la
description de ces types en utilisant le vocabulaire schema.org et en
concatenant les résultats par type, par exemple :
library(WikidataQueryServiceR)
library(DT)
## Chercher les instances des collections du graphe Wikidata qui contiennent une oeuvre de Vermeer
#- ensemble d'un même type de collections dont l'oeuvre du peintre est membre
id_collections <- paste("?collections")
id_description <- paste("?description")
#- concatener des objets dans des ensembles de type de collections
concatener <- paste0("(group_concat(",id_objet,") AS ",id_collections,")")
#- propriétés utilisées
propriete_description <- paste0("description")
## Construire les chemins du graphe pour les propriétés de différents types (et entités associées)
#- prédicats utilisés
prefixe_schema <- paste0("schema:")
predicat_description <- paste0(prefixe_schema,propriete_description)
#- chercher les objets collections contenant des oeuvres de Vermeer
chemin_description <- paste(type_id_objet,predicat_description,id_description)
chemins_du_graphe <- paste(chemin_primaire,".",chemin_type,".",chemin_description)
## Grouper
groupe <- paste("GROUP BY",nom_type_id_objet,id_description)
## Construire la requête
#- Filtre de langue des noms
filtre_langue <- paste0("FILTER(lang(",id_description,")=\"fr\")")
query <- paste("SELECT",nom_type_id_objet,id_description,concatener,"WHERE {",service,chemins_du_graphe,filtre_langue,"}",groupe)
## Exécuter la requête
metadonnees_description_collections_comme_objet <- query_wikidata(query)
## Afficher le résultat
datatable(metadonnees_description_collections_comme_objet)Le résultat avec la description des types d’instances de Wikidata répondant à la question des collections au sein desquelles les oeuvres de Vermeer se trouvent confirme le caractère hétérogène et donc l’impossibilité d’exploiter ce chemin du graphe. Revenons alors aux oeuvres elles-mêmes.
3.4.5 Choisir l’oeuvre de Vermeer qui a le plus voyagé
library(WikidataQueryServiceR)
library(DT)
## Données wikidata recherchées
nom_id_oeuvre[1] "?oeuvreLabel"
donnees_interrogees <- paste0(nom_id_oeuvre)
#- compteur et comptage de ces objets associés aux propriétés interrogées
comptage <- paste0("(COUNT(DISTINCT",val_pointxy,") AS ",compteur,")")
#-grouper et ordonner
ordre_decroissant <- paste0("ORDER BY DESC(",compteur,")")
grouper <- paste("GROUP BY",donnees_interrogees)
groupe_et_ordonne <- paste(grouper,ordre_decroissant)
## Construire les chemins du graphe
#- Prédicat utilisés
predicat_lieu_declaration <- paste0(prefixe_propriete_directe,propriete_lieu,"/",prefixe_propriete_declarative,propriete_lieu)
#- Chemins du graphe
chemin_principal <- paste(id_oeuvre,predicat_creepar_declaration,entite_vermeer)
chemin_lieu <- paste(id_oeuvre,predicat_lieu_declaration,id_lieu)
chemin_coord <- paste(id_lieu,predicat_coord,val_pointxy)
chemins_du_graphe <- paste(chemin_principal,".",chemin_lieu,".",chemin_coord)
chemins_du_graphe[1] "?oeuvre p:P170/ps:P170 wd:Q41264 . ?oeuvre p:P276/ps:P276 ?musee . ?musee wdt:P625 ?coord"
## Construire la requête
query <- paste("SELECT",donnees_interrogees,comptage,"WHERE {",chemins_du_graphe,service,"}",groupe_et_ordonne)
## Exécuter la requête
metadonnees_localisation_oeuvres <- query_wikidata(query)
## Affiche le résultat
datatable(metadonnees_localisation_oeuvres)L’œuvre intitulée “Dame assise au virginal” (entité Q4660880) est, selon
Wikidata, l’œuvre de Johannes Vermeer qui a le plus voyagé pour être
exposée. Cela signifie que cette entité possède le plus grand nombre de
valeurs associées à la propriété “lieu” (propriété P276) dans les déclarations exhaustives de
localisation désignant des lieux (prédicat de préfixe ps:),
dont les coordonnées sont données par la propriété simple (prédicat de
préfixe wdt:) P625.
Ce constat ouvre une nouvelle perspective en matière d’analyse
exploratoire. Nous allons donc nous intéresser à la trajectoire
spatio-temporelle de cette œuvre.
3.5 Troisième requête SPARQL : déclaration spatiale et temporelle
Comme illustré dans les figures 6b et 6c, la localisation
spatio-temporelle d’une entité est déclarée au moyen d’une propriété (P276), qui permet
l’accès à: - une localisation de l’œuvre dans un lieu (géographique
et institutionnel) : P276, associée à l’ensemble des
déclarations de localisations spatio-temporelles liées au sujet du
prédicat à savoir,
- les localisations géogrpahiques (voir Figures 6b ou 6c), - elles-mêmes
liées dans le temps aux propriétés dites qualifiers
de la déclaration de lieu (désignées par le préfixe pq:)
donnant une période temporelle (date de début : P580, date de
fin: P582) ou
date/point dans le temps d’un événement P585.
library(WikidataQueryServiceR)
library(DT)
## Chercher les déclarations des lieux du graphe Wikidata qui contiennent l'oeuvre de Vermeer dont l'identifiant est `Q4660880`
#- objets (et type de ceux-ci) de la propriété recherchée "est collection", dont l'oeuvre du peintre est membre
id_date_debut <- paste("?dated")
id_date_fin <- paste("?datef")
id_localisation <- paste("?lieu")
qid_oeuvre <- paste0("Q4660880")
entite_oeuvre <- paste0(prefixe_entite,qid_oeuvre)
id_image <- paste("?image")
#- données interrogées
donnees_interrogees <- paste(nom_id_lieu,id_date_debut,id_date_fin,val_pointxy)
#- propriétés utilisées
propriete_date_debut <- paste0("P580")
propriete_date_fin <- paste0("P582")
## Construire les chemins du graphe pour les propriétés de différents types (et entités associées)
#- prédicats utilisés
predicat_lieu_direct <- paste0(prefixe_propriete_directe,propriete_lieu)
predicat_lieu_declaratif <- paste0(prefixe_propriete_declarative,propriete_lieu)
prefixe_qualificatif <- paste0("pq:")
predicat_date_debut_qualificatif <- paste0(prefixe_qualificatif,propriete_date_debut)
predicat_date_fin_qualificatif <- paste0(prefixe_qualificatif,propriete_date_fin)
#- chercher les objets collections contenant des oeuvres de Vermeer
chemin_primaire <- paste(entite_oeuvre,predicat_lieu_direct,id_localisation)
chemin_coord <- paste(id_localisation,predicat_lieu_declaratif,id_lieu,".",id_lieu,predicat_coord,val_pointxy)
chemin_date_debut <- paste(id_localisation,predicat_date_debut_qualificatif,id_date_debut)
chemin_date_fin <- paste(id_localisation,predicat_date_fin_qualificatif,id_date_fin)
chemin_image <- paste(entite_oeuvre,predicat_image,id_image)
chemins_du_graphe <- paste(chemin_primaire,".",chemin_coord,".",chemin_date_debut,".",chemin_date_fin,".")
## Construire la requête
query <- paste("SELECT",donnees_interrogees,"WHERE {",service,chemins_du_graphe,"}")
query_image <- paste("SELECT",id_image,"WHERE {",chemin_image,"}")
## Exécuter la requête
metadonnees_lieu_temps_oeuvre <- query_wikidata(query)
url_image <- query_wikidata(query_image)
## Afficher le résultat
datatable(metadonnees_lieu_temps_oeuvre) knitr::include_graphics(url_image$image)library(glitter)
data <- spq_init() |>
spq_add("wd:Q4660880 wdt:P18 ?image") |>
spq_add("wd:Q4660880 p:P276 ?location") |>
spq_add("?location ps:P276 ?nom",.label="?nom") |>
spq_add("?location pq:P580 ?dated") |>
spq_add("?location pq:P582 ?datef") |>
spq_add("?nom wdt:P625 ?coord") |>
spq_select(musee = nomLabel) |>
spq_perform() Affichage d’une partie des données récupérées :
Enregistrement et (ré)import des données :
# Enregistrement des données en format csv
write.csv(x = data, file = "data/data.csv", row.names = FALSE)
# Import du fichier de données enregistrées
data <- read.csv("data/data.csv", row.names = NULL)Enregistrement de l’image de l’œuvre :
download.file(url = data$image[1],
destfile = 'data/images/Q4660880.jpg',
mode = 'wb')Les trois requêtes SPARQL ont ainsi permis de collecter respectivement :
- l’image et l’identifiant associés à Johannes Vermeer dans Wikidata (data1) ;
- les œuvres du peintre Johannes Vermeer et leur localisation (musée + coordonnées) (data2) ;
- les informations de localisation (nom du musée, coordonnées et dates) des lieux où a été exposée l’œuvre A Young Woman Seated at the Virginals de Johannes Vermeer (data).
4 Exploration spatiale
Les données non-supervisées collectées nécessitent toujours d’être contrôlées et nettoyées avant d’être exploitées. De plus, les données obtenues comportent des coordonnées géographiques qui permettent de les convertir en véritable couche géographique afin de les cartographier et ainsi d’exploiter leur dimension spatiale.
4.1 Les œuvres de Johannes Vermeer
Les données issues de la seconde requête SPARQL (data2) listent l’ensemble des œuvres de Vermeer et leurs localisations respectives (nom du musée et coordonnées géographiques quand elles existent) selon Wikidata. Avant de les cartographier, quelques traitements sont nécessaires :
- Suppression des doublons et des œuvres sans aucune localisation renseignée ;
- Calcul du nombre d’œuvres par musée (localisation) ;
- Géoréférencement7 des musées abritant des œuvres de Vermeer.
4.1.1 Nettoyage des données
Dans cette partie, nous allons uniquement nous intéresser à la dimension spatiale des données collectées, sans prendre en compte la dimension temporelle. Si aucune coordonnée géographique n’est renseignée (cf. partie 3.3), nous ne prendrons pas en compte le musée recensé. En revanche, nous considérons l’ensemble des localisations comportant des coordonnées géographiques, peu importe la temporalité qui leur est associée.
Commençons par supprimer les localisations (musée ou institution) qui ne sont pas associées à des coordonnées géographiques dans Wikidata :
data2 <- data2[!is.na(data2$coord), ]Nous pouvons ensuite supprimer les doublons, que l’on peut expliquer par le fait qu’une œuvre ait pu être exposée à plusieurs reprises dans un même musée, ou qu’un même lieu ait pu être renseigné par plusieurs couples de coordonnées géographiques dans Wikidata.
Pour cela, nous utilisons la fonction duplicated,
appliquée au couple “nom de l’œuvre + lieu d’exposition”
data2 <- data2[!duplicated(data2[, c("oeuvreLabel", "museeLabel")]), ]Affichage des données filtrées :
datatable(data2)4.1.2 Regroupement par musée
Plusieurs œuvres semblent avoir été exposées dans les mêmes lieux. Afin de cartographier les musées ayant exposé différentes œuvres de Johannes Vermeer, nous réalisons un regroupement des œuvres par intitulé des musées (museeLabel), tout en calculant le nombre d’œuvres que chacune de ces institutions a exposées au cours du temps.
–>
# Regroupement et calcul du nombre d'œuvres par musée
library(dplyr)
nb_oeuvres_musee <- data2 |>
group_by(musee = museeLabel, coords = coord) |>
summarise(nb_oeuvres = n())
# Histogramme de répartition des musées en fonction du nombre d'œuvres de J.V. exposées
library(ggplot2)
ggplot(nb_oeuvres_musee, aes(x = nb_oeuvres)) +
geom_histogram(breaks = 0:max(nb_oeuvres_musee$nb_oeuvres), col = "white") +
xlab("Nombre d'œuvres exposées") +
ylab("Nombre de musées")4.1.3 Géoréférencement
La variable ‘coords’ stocke les coordonnées géographiques des musées
dans le format WKT8 (Well-known text). A l’aide du package
sf, il est simple de construire des données géographiques
vectorielles permettant l’analyse spatiale avec R (Simple Features object) à partir de ce
format de stockage. Pour cela, nous utilisons les fonctions
st_as_sfc et st_as_sf.
# Chargement du package sf, pour la gestion de données géographiques vectorielles
library(sf)
# Création d'objets géographiques ponctuels à partir des coordonnées stockées en WKT
geometry <- st_as_sfc(nb_oeuvres_musee$coords, crs = 4326)
# Création d'une couche géographique vectorielle (attributs des musées + géométries)
musee_geo <- st_as_sf(nb_oeuvres_musee, geometry)La table de données a été transformée en couche géographique
manipulable avec R (objet sf), où chaque musée comporte une
géométrie (point localisé dans l’espace, dans le système géographique de
référence WGS84).
Il est maintenant très simple de cartographier les points créés
(musées) sur une carte interactive, en utilisant le package
mapview. Cela permet, entre autres, de vérifier la qualité
des données et du géoréférencement effectué.
# Package pour la cartographie interactive (repose sur la librairie Leaflet)
library(mapview)
# Affichage interactif des musées, sur un fond de carte OpenStreetMap
mapview(musee_geo) 4.1.4 Cartographie thématique
À partir des données collectées et pré-traitées, il est possible de construire une carte interactive en symboles proportionnels représentant le nombre d’œuvres de Johannes Vermeer exposées par musée au cours du temps.
# Package de cartographie thématique
library(tmap)
# Activation du mode de cartographie interactive
tmap_mode(mode = "view")
# Carte en symboles proportionnels
tm_basemap() +
tm_shape(musee_geo) +
tm_symbols(size="nb_oeuvres",
scale = 4,
col="red3",
border.col="white",
alpha =0.5,
border.lwd=0.1,
border.alpha=0.5,
id = "musee",
popup.vars=c("Nombre d'œuvres :"="nb_oeuvres" ))4.1.5 Enrichissement des données
Au vue de la carte précédente, il semble intéressant d’explorer la répartition des œuvres de Johannes Vermeer à l’échelle des pays. Pour cela, il est nécessaire d’enrichir les données. Plusieurs étapes sont nécessaires :
Téléchargement d’un fond de carte pays mis à disposition par
le package rnaturalearth:
# Package permettant d'utiliser l'API de Natural Earth
library(rnaturalearth)
# Téléchargement et enregistrement d'un fond de carte "pays"
monde <- ne_download(scale = "medium",
type = "countries",
category = "cultural",
destdir = "data/world",
load = TRUE,
returnclass = "sf")Le fond de carte récupéré est également mis à disposition dans les données
téléchargeables. Vous pouvez le charger dans R à l’aide du package
sf et de sa fonction st_read() de la façon
suivante :
monde <- st_read("data/world/ne_50m_admin_0_countries.shp", quiet = TRUE ) Affichage de la couche géographique :
plot(st_geometry(monde))Les attributs des entités (pays) de la couche géographique récupérée sont :
La couche géographique des musées (‘musee_geo’) et le fond de carte
du monde (‘monde’) sont géoréférencés dans le même système de
coordonnées9 (le WGS84). Nous pouvons
donc réaliser une jointure spatiale qui permet de récupérer pour
chaque musée, le code
ISO3 du pays dans lequel il se situe. Pour cela, nous utilisons la
fonction st_intersection du package sf.
Jointure spatiale entre les musées (points) et les pays (polygones) :
musee_geo <- st_intersection(musee_geo, monde[, "ADM0_A3"])Le code ISO3 du pays de localisation (“ADM0_A3”) a été ajouté à la couche géographique des musées :
4.1.6 Répartition par pays
Le pays de localisation de chaque musée ayant été obtenu, nous pouvons réaliser une représentation graphique de cette distibution spatiale.
Commençons par calculer le nombre total d’œuvres exposées par pays :
nb_oeuvres_pays <- musee_geo |>
group_by(ADM0_A3) |>
summarise(nb_oeuvres=sum(nb_oeuvres))Nous pouvons ensuite construire un graphique en utilisant le package
de référence ggplot2.
# Package pour la représentation graphique
library(ggplot2)
# Graphique en barre - Nombre d'œuvres par pays
ggplot(data = nb_oeuvres_pays,
aes(x = reorder(ADM0_A3, -nb_oeuvres),
y = nb_oeuvres, fill = ADM0_A3)) +
geom_bar(stat = "identity") +
ggtitle("Nombre d'œuvres de Johannes Vermeer exposées, par pays") +
xlab("") +
ylab("") +
scale_fill_manual(values = c("#FC8D62", "#80B1D3" ,"#E78AC3",
"#A6D854","#FFD92F","#E5C494",
"#FB8072","#BEBADA","#66C2A5",
"#FFFFB3","#8DA0CB")) +
annotate(geom="text",
x = 9, y = 13,
label = "Une œuvre peut\navoir été exposée\ndans plusieurs pays" ) +
theme(legend.position = "none")4.2 La ‘Dame assise au virginal’
Les données issues de la troisième requête SPARQL (‘data’) contiennent l’ensemble des localisations renseignées pour l’œuvre de Johannes Vermeer A Young Woman Seated at the Virginals (ou Dame assise au virginal en français). Nous allons donc réaliser un processus de nettoyage et de géoréférencement très semblable à celui de la partie précédente.
4.2.1 Nettoyage des données
Suppression des doublons :
data <- data[!duplicated(data$dated), ]4.2.2 Géoréférencement
Géoréférencement des musées à partir de la variable ‘coord’ :
# Création d'objets géographiques ponctuels à partir des coordonnées stockées en WKT
geometry <- st_as_sfc(data$coord, crs = 4326)
# Création d'une couche géographique vectorielle (attributs des musées + géométries)
data_geo <- st_as_sf(data, geometry)
# Affichage des données
datatable(data_geo)Plusieurs musées, comme le Ashmolean Museum, apparaissent plusieurs fois dans la table car l’œuvre y a fait plusieurs séjours. Nous effectuons un regroupement des expositions par musée.
# Regroupement par musée - Calcul du nombre total d'expositions
nb_expos_musee_geo <- data_geo |>
group_by(musee) |>
summarise(nb_expos=n())Il est facile d’afficher ces données géographiques ponctuelles sur un fond de carte dynamique, en améliorant cette fois-ci la mise en page des pop-ups contenant les attributs de chaque musée.
# Popup content
content <- paste0( "<img src='",
"http://commons.wikimedia.org/wiki/Special:FilePath/Vermeer%20-%20A%20young%20Woman%20seated%20at%20the%20Virginals.jpg",
"' width='180'><br /><b>",
nb_expos_musee_geo$musee,
"</b><br />Nombre d'expositions de l'œuvre : <b>",
nb_expos_musee_geo$nb_expos,
"</b>")
# Carte
mapview(nb_expos_musee_geo,
zcol = "musee",
col.regions = "red",
legend = FALSE,
popup = content,
map.types = "Esri.WorldImagery")4.2.3 Enrichissement des données
De la même manière que dans la partie 4.1.5, nous enrichissons
ces données en obtenant le pays de localisation de chaque musée. Pour
cela, nous réalisons une jointure spatiale en utilisant la fonction
st_intersection du package sf.
# Jointure spatiale points/pays
data_geo <-st_intersection(data_geo, monde[,"ADM0_A3"])On vérifie que le code ISO3 du pays a bien été collecté pour chaque point (musée).
5 Trajectoire spatio-temporelle
Nous allons mainenant prendre en compte la dimension temporelle des données collectées, c’est à dire la période d’exposition du tableau A Young Woman Seated at the Virginals dans chaque musée, comme renseigné dans Wikidata.
5.1 Période d’exposition du tableau
Pour manipuler facilement le temps, nous commençons par convertir les
dates d’arrivée et de départ de l’œuvre dans chaque musée en format de
type date.
data_geo$datef <- as.Date(data_geo$datef)
data_geo$dated <- as.Date(data_geo$dated)Il est ensuite simple de calculer le nombre de jours de présence dans un musée avec une soustraction. Nous sauvegardons ces valeurs (nombre de jours) dans une nouvelle colonne (‘duree’).
data_geo$duree <- as.integer(data_geo$datef - data_geo$dated)Le tableau a été exposé à deux reprises dans plusieurs musées. Nous calculons donc le nombre de jour total d’exposition du tableau par musée.
data_musee <- data_geo |>
group_by(musee, ADM0_A3) |>
summarise(duree = sum(duree),
nb_expos = n())Plusieurs informations collectées peuvent être cartographiées. Voici
un exemple de carte interactive réalisée avec le package
tmap, qui représente le nombre de jours d’exposition du
tableau au cours du temps, à l’échelle des musées.
# Activation du mode de cartographie interactive
tmap_mode(mode = "view")
# Construction d'une carte en symbole proportionnel
tm_basemap() +
tm_shape(data_musee) +
tm_bubbles("duree",
col = "ADM0_A3",
scale = 9,
border.col="white",
alpha = 0.7,
border.lwd=0.1,
border.alpha=0.5,
title.col="Pays d'exposition",
id = "musee",
popup.vars=c("Nombre total de jours :"="duree",
"Nombre total de séjours :"="nb_expos"))5.2 Carte temporelle animée
La carte précédente ne permet pas de rendre compte de la trajectoire spatio-temporelle de l’œuvre. Une carte animée représentant la localisation de l’œuvre au cours du temps permettrait de formaliser son déplacement dans l’espace et dans le temps.
Pour cela, nous devons dans un premier temps choisir un pas de temps. La période de temps analysée est de presque 20 ans et le tableau peut avoir été exposé dans deux musées différents au cours d’un même mois. Nous choisissons donc de construire une carte animée réglée sur un pas de temps hebdomadaire, ce qui laissera le temps aux lecteur·rice·s de lire les informations affichées.
Un partir de ce pas de temps, nous créons un data.frame
où chaque ligne représente une semaine calendaire située entre le 8 mars
2001 et le 13 Janvier 2019 à l’aide de la fonction seq.
Nous créons également des colonnes vides qui permettront de stocker
l’ensemble des informations de localisation de l’œuvre pour chaque
semaine.
data_semaine<- data.frame(semaine = seq(min(data_geo$dated), max(data_geo$datef), "week"),
musee = as.character(NA),
duree = as.integer(NA),
pays = as.character(NA),
geometry = NA)Une boucle for permet de parcourir le tableau et
d’obtenir les informations de localisation de l’œuvre si la date du
premier jour d’une semaine ciblée data_semaine$week[i] est
située entre une date d’arrivée et de départ dans le tableau
data_geo. Si c’est le cas, on inscrit les informations du
tableau data_geodans le tableau
data_semaine.
for (i in 1:nrow(data_semaine)){
# Sélection des lignes où : Date d'arrivée <= week[i] <= Date de départ
temp <- data_geo[data_geo$dated <= data_semaine$semaine[i] & data_geo$datef >= data_semaine$semaine[i], c("musee", "duree", "ADM0_A3", "geometry")]
# Si une ligne est sélectionnée, on l'ajoute dans l'objet 'data_semaine'
if (nrow(temp)==1){data_semaine[i,2:5] <- temp}
}Nous modifions ensuite les valeurs restées manquantes, pour les semaines où la peinture n’a pas été exposée.
data_semaine <- data_semaine |>
mutate(
# si musee non renseigné, remplace par "Emplacement inconnu"
musee=case_when(is.na(musee)~"Emplacement inconnu", TRUE~musee),
# si pays non renseigné, remplace par "pays ?"
pays=case_when(is.na(pays)~"pays ?", TRUE~pays),
# si duree non renseignée, remplace par 0
duree=case_when(is.na(duree)~0, TRUE~duree)
)
# Affichage du tableau
datatable(data_semaine)Bien que ce tableau possède une colonne geometry, il
s’agit en fait d’un data.frame. Nous le convertissons en
objet sf (couche géographique).
data_semaine <-st_as_sf(data_semaine)Les données sont prêtes pour créer une carte animée qui représente la
localisation de l’œuvre pour chaque semaine calendaire de 2001 à 2019.
Pour cela, nous utilisons le package tmap, son mode
plot (cartographique statique), sa fonction
tm_facet (génère plusieurs cartes en fonction d’une
variable) et sa fonction tmap_animation pour créer une
carte animée en format vidéo.
# Cartographie en mode statique
tmap_mode(mode = "plot")
# Création d'une carte stockée dans l'objet CARTE
CARTE <- tm_shape(monde) + # Ajout fond de carte monde
tm_polygons(col = "grey70",
border.col = "grey60",
border.lwd = 0.2) +
tm_shape(data_semaine) + # Ajout des musées, mais...
tm_symbols(col = "red") +
tm_facets(along = "semaine", # Une carte / semaine grâce à tm_facet
free.coords= FALSE,
drop.units=FALSE) +
tm_layout(main.title ="", # Gestion du titre
panel.label.fontface = 2,
panel.labels = paste0("Semaine du ", format(x = data_semaine$semaine, format = "%d %b %Y" )),
bg.color="lightblue") +
tm_credits(bg.color = 'red', # Affichage Nom des musées et Nombre de jours d'exposition
width = 0.5,
position = c('center', 'bottom'),
text = paste0(data_semaine$musee," (",data_semaine$pays,")\n",data_semaine$duree, " jours d'exposition"),
size = 1.2,
fontface = "bold",
col = 'white',
align = 'center')Avec la fonction tm_facet, ce bout de code crée autant
de cartes qu’il y a de lignes dans le tableau
data_semaine.
Il est ensuite très facile de convertir cet objet list
qui contient l’ensemble des cartes produites en fichier mp4 avec la
fonction tmap_animation. Attention, la création
d’un GIF ou d’une vidéo peut prendre plusieurs minutes.
# install.packages("av")
tmap_animation(tm = CARTE,
filename = "figures/peinture_en_voyage.mp4",
width=800,
height = 400,
fps = 10, # images par seconde
outer.margins = 0)av est nécessaire pour créer
des vidéos avec la fonction tmap_animation. Cette fonction
permet également de créer des GIFs animés, mais il vous sera également
nécessaire d’installer le package gifski pour profiter de
cette fonctionnalité .
Voilà le résultat !
6 Frise chronologique
Bien que la carte animée soit une représentation techniquement aboutie, elle ne transmet pas efficacement les informations sur la trajectoire spatio-temporelle du tableau de Johannes Vermeer au monde des musées. Une représentation statique et axée sur la dimension temporelle, comme une frise chronologique, nous semblerait plus appropriée.
Il existe des packages spécialisés dans la construction de frise
chronologique, comme par exemple vistime. Cependant, afin de s’assurer
d’une certaine liberté pour la mise en forme de la frise, nous utilisons
le package ggplot2 pour concevoir et construire cette
représentation graphique.
6.1 Préparation des données
Une mise en forme des données est nécessaire pour construire ce type
de frise chronologique avec ggplot2. Par exemple, le tri
des données est important pour gérer l’ordre d’apparition des individus
et des modalités sur le graphique.
Tri du tableau en fonction de la date (‘dated’) d’arrivée dans chaque musée.
data_geo <- data_geo[order(data_geo$dated, decreasing = FALSE), ] Tri d’ordre d’apparition des modalités (levels) pour
les variables ‘nomLabel’ (= ‘musee’) et ‘ADM0_A3’ (= ‘pays’) que l’on
transforme en factor.
# Tri des "levels" des musées en fonction de l'ordre d'apparition dans la table 'data_geo'
data_geo$musee <- ordered(as.factor(data_geo$nomLabel), levels = unique(data_geo$nomLabel))
# Tri des "levels" des pays en fonction de l'ordre d'apparition dans la table 'data_geo'
data_geo$pays <- ordered(as.factor(data_geo$ADM0_A3), levels = unique(data_geo$ADM0_A3))Nous créons une nouvelle colonne qui sera utilisée comme étiquette dans le graphique. Dans cette colonne, les noms des musées n’apparaissent qu’une fois, uniquement pour la première exposition.
# Sélection des premières dates d'arrivée (si il en existe plusieurs) pour chaque musée
fisrt_expo <- data_geo[!duplicated(data_geo$nomLabel), c("nomLabel", "dated")]
# Suppression de la colonne géométrie pour réaliser une jointure
fisrt_expo <- st_drop_geometry(fisrt_expo)
# Jointure par la date d'arrivée - ajout de la colonne label (nomLabel.y)
data_geo <- merge(data_geo, fisrt_expo, by="dated", all.x=TRUE)Tableau de données après traitement (extrait) :
6.2 Construction graphique
6.2.1 Utilisation des
fonctions ggplot() et geom_segement()
Les variables utilisées pour l’axe des abscisses (x) et des ordonnées
(y) sont définies comme suit dans la fonction ggplot :
- X = ‘dated’ : date d’arrivée dans le musée ;
- y = ‘nomLabel.x’ : nom du musée (label unique).
ggplot(data_geo, aes(x = dated, y = musee))La bibliothèque ggplot2 fonctionne avec une syntaxe
particulière (basée sur la grammaire graphique). Il est possible d’ajouter des
éléments de mise en forme du graphique au fur et à mesure.
Nous commençons par préciser le type de géometrie (ici
geom_segment) et les variables à représenter :
- color = ‘ADM0_A3’ (code ISO3) : pays de localisation ;
- xend = ‘datef’ (date de fin) : limite du segment en x ;
- yend = ‘nomLabel.x’ (nom du musée) : limite du segment en y.
# Construction de 'segments' entre la date d'arrivée (dated) et de départ (datef)
ggplot(data_geo, aes(x = dated, y = musee, color = pays)) +
geom_segment(aes(xend = datef, yend = musee, color = pays), size = 6)Nous assignons le résultat dans un objet :
Mon_graph <- ggplot(data_geo, aes(x = dated, y = musee, color = pays)) +
geom_segment(aes(xend = datef, yend = musee, color = pays), size = 6)6.2.2 Couleurs, étiquettes et thème
Maintenant que la base du graphique a été réalisée, nous pouvons procéder à l’amélioration de sa mise en forme en plusieurs étapes :
- ajout des labels avec la fonction
geom_text; - modification de la palette de couleurs avec la fonction
scale_color_manual;
Mon_graph <- Mon_graph +
# Ajout d'une étiquette pour chaque segment représenté
geom_text(aes(label = nomLabel.y, hjust =1.05), size = 3.5, show.legend = FALSE) +
# Modification de la palette de couleurs (ADM0_A3)
scale_color_manual(values = c("#7570b3", "#e7298a", "#66a61e", "#e6ab02", "#a6761d","#1b9e77", "#d95f02"))
# Affichage du résultat
Mon_graphPuis, à l’aide des fonctions scale_x_date
labs et theme :
- modification de l’axe des abscisses (intervalle des valeurs et étiquettes à afficher) ;
- ajout d’un titre et d’un sous-titre ;
- paramétrage de plusieurs éléments du ‘thème’ (repère, légende, axes, couleur de fond…).
Mon_graph <- Mon_graph +
# Modification de l'axe des abscisses
scale_x_date(date_labels = "%Y", date_breaks = "2 year", minor_breaks = "1 year",
limits = c(as.Date("1994-01-01"),as.Date("2019-01-13")) ) +
# Ajout d'un titre et d'un sous-titre
labs(title = "Le voyage d'un tableau de Johannes Vermeer",
subtitle = "Aux pays des musées, de 2001 à 2019") +
# Paramétrage du 'thème'
theme(panel.grid.major.y = element_blank(),
panel.grid.major.x = element_line(size = 0.2, colour = "#707073"),
panel.grid.minor.x = element_line(size = 0.2, linetype = 3, colour = "#707073"),
panel.border = element_blank(),
panel.background = element_blank(),
axis.text.y = element_blank(),
axis.text.x = element_text(size=8.5, colour = "#FFFFFF"),
axis.title = element_blank(),
rect = element_rect(fill = "#2a2a2b"),
legend.position = c(.93, .25),
legend.key = element_rect(fill = "#2a2a2b"),
legend.key.height = unit(0.4, 'cm'),
legend.background = element_rect(fill = "#2a2a2b"),
legend.margin = margin(0.5,1,1,1),
legend.title = element_blank(),
legend.text = element_text(colour = "#FFFFFF", size = 7),
title = element_text(colour = "#FFFFFF", hjust = 1, vjust = 0),
plot.margin=unit(c(1,1,0.5,1),"cm"))
Mon_graph6.2.3 La touche finale !
Pour terminer la mise en forme de cette frise chronologique,
l’illustration du tableau et son intitulé sont superposés au graphique.
Les bibliothèques jpeg et patchwork nous
permettent d’importer, puis d’insérer une image sur la représentation
graphique.
Import de l’image du tableau dans R
library(jpeg)
img <- readJPEG("data/images/Q4660880.jpg", native = TRUE)Superposition de l’image et de la représentation graphique
library(patchwork)
Mon_graph +
# Titre de l'image
annotate("text",
x = as.Date("1997-03-01"),
y = 7,
colour = "#FFFFFF",
size = 3.4,
label = "Young Woman Seated\nat a Virginal (1670)") +
# Insertion de l'image
inset_element(p = img,
clip = TRUE,
left = 0.04,
right = 0.27,
top = 0.95,
bottom = 0.46)7 À vous d’explorer !
Nous vous proposons d’explorer vous-mêmes le contenu des données
Wikidata. Le bout de code ci-dessous peut être adapté à n’importe
quel·le artiste peintre renseigné·e dans Wikidata. Il suffit de
modifier l’identiant de l’artiste assigné·e dans l’objet
ID et son nom dans l’objet NOM.
Vous pouvez retrouver l’identifiant Wikidata d’un·e artiste peintre sur la page Wikidata. Indiquez le nom de l’artiste peintre dont vous souhaitez localiser les œuvres dans le champ de recherche. Veillez à bien récupérer l’identifiant correspondant à l’entité ‘artiste’.
7.1 Code reproductible
Voici quelques exmples d’artistes peintres que vous pouvez requêter :
- Salvador Dalí Q5577 ;
- Nandalal Bose Q3348980 ;
- Kalervo Palsa Q320590 ;
- Katsushika Hokusai Q5586 ;
- Edvard Munch Q41406 ;
- Pablo Picasso Q5593.
#-------------------------------------------------------------------------------------------------#
# #
# Exploration spatio-temporelle #
# de l'exposition des œuvres de ??? #
# Selon Wikidata #
# #
#-------------------------------------------------------------------------------------------------#
#--------------------------------------- PACKAGES NECESSAIRES ------------------------------------#
# install.packages("WikidataQueryServiceR")
# install.packages("sf")
# install.packages("rnaturalearth")
# install.packages("ggplot2")
# install.packages("tmap")
######################################### CHOIX DE L'ARTISTE ######################################
ID <- "Q5593"
NOM <- "Pablo Picasso"
#---------------------------------------------- REQUETE ------------------------------------------#
# Construction de la requête SPARQL avec l'identifiant (ID) indiqué
query <- paste0("SELECT ?oeuvreLabel ?museeLabel ?coord WHERE { SERVICE wikibase:label { bd:serviceParam wikibase:language '[AUTO_LANGUAGE],en'. } ?oeuvre wdt:P170 wd:", ID, " . OPTIONAL {?oeuvre p:P276 ?loc . ?loc ps:P276 ?musee . ?musee wdt:P625 ?coord} . }")
library(WikidataQueryServiceR)
my_data <- query_wikidata(query)
#----------------------------------------- NETTOYAGE DONNEES -------------------------------------#
# Suppression des doublons
my_data <- my_data[!duplicated(my_data$oeuvreLabel), ]
# Suppression entités (musées et institutions) sans coordonnées renseignées
my_data <- my_data[!is.na(my_data$coord), ]
#-------------------------------------- REGROUPEMENT PAR MUSEE -----------------------------------#
nb_oeuvre <- aggregate(oeuvreLabel ~ coord + museeLabel, data = my_data, FUN = length)
colnames(nb_oeuvre)[3] <- "nb_oeuvre"
#----------------------------------------- GEOREFERENCEMENT --------------------------------------#
# Chargement de la librairie sf
library(sf)
# Création d'objets géographiques ponctuels à partir des coordonnées stockées en WKT
geometry <- st_as_sfc(nb_oeuvre$coord, crs = 4326)
# Création d'une couche géographique vectorielle (attributs des musées + géométries)
nb_oeuvre_by_museum <- st_as_sf(nb_oeuvre, geometry)
#------------------------------- ENRICHISSEMENT - JOINTURE SPATIALE -----------------------------#
#### Import de la couche géographique des pays
library(rnaturalearth)
monde <- ne_download(scale = "medium",
type = "countries",
category = "cultural",
destdir = "data/world",
load = TRUE,
returnclass = "sf")
#### Jointure spatiale
nb_oeuvre_by_museum <-st_intersection(nb_oeuvre_by_museum , monde[,"ADM0_A3"])
#---------------------------------- GRAPHIQUE NOMBRE ŒUVRES PAR PAYS ----------------------------#
#### Regroupement par pays
by_country <- aggregate(nb_oeuvre ~ ADM0_A3 , data = nb_oeuvre_by_museum, FUN = sum)
#### Graphique
library(ggplot2)
ggplot(data = by_country, aes(x = ADM0_A3, y = nb_oeuvre) ) +
geom_bar(stat="identity") +
ggtitle(paste0("Nombre d'œuvres de ", NOM ,", par pays")) +
xlab("") +
ylab("") +
theme(legend.position = "none",
axis.text.x = element_text(size=8),
axis.text.y = element_text(size=11))
#----------------------------- CARTOGRAPHIE - NOMBRE ŒUVRES PAR MUSEE ---------------------------#
library(tmap)
tmap_mode(mode = "view")
tm_shape(nb_oeuvre_by_museum) +
tm_symbols(size="nb_oeuvre",
scale = 2,
col="red3",
border.col="white",
alpha =0.5,
border.lwd=0.1,
border.alpha=0.5,
title.size = "Nb d'œuvres",
id = "museeLabel",
popup.vars=c("Nombre d'œuvres"="nb_oeuvre"))7.2 Données et graphiques produits
Voici un exemple des données et graphiques produits avec l’artiste peintre et graveur norvégien Edvard Munch, ayant pour identifiant Wikidata : Q41406.
ID <- "Q41406"
NOM <- "Edvard Munch"Dans un premier temps, le code permet de collecter l’ensemble des œuvres créees par l’artiste, ainsi que leurs localisations associées via une requête SPARQL. Voici par exemple les données collectées pour Edvard Munch :
Les données sont ensuite nettoyées des doublons et des œuvres qui ne sont jamais associées à des coordonnées géographiques précises, puis regroupées par musée :
Les musées sont alors géoréférencés, ce qui permet de réaliser une jointure spatiale avec une couche géographique des pays, et ainsi d’obtenir leur pays de localisation. Le code produit également une représentation graphique de la répartition des expositions des œuvres par pays :
Enfin, le code construit une carte interactive représentant le nombre d’œuvres exposées par musée :
8 Conclusion - Enjeux interdisciplinaires
L’exemple de visualisations (distant reading) d’une trajectoire spatio-temporelle en histoire à partir de données collectées sur Wikidata propose ainsi de questionner les données utilisées (non supervisées).
Notamment la circulation de l’oeuvre fait apparaître des espaces spatio-temporels où celle-ci est absente des lieux d’exposition. Ce constat engage à ré-interroger les données et le modèle associé. Par exemple, sur la période antérieur à 2004, l’étude de la donnée permet d’identifier la propriété P195 collection qui identifie la collection à laquelle appartient l’œuvre. Le lien hypertexte servant de référence à cette donnée (à savoir la propriété P195 collection appliquée à Q4660880 instanciée par Leiden Collection) donne alors accès aux informations de transfert de propriété en 2004 des héritiers du Baron Frédéric Rolin (Bruxelles) à un américain Steve Wynn qui lui-même la cède la même année à la société Otto Naumann Ltd. (New York), qui fait entrer l’œuvre dans son catalogue au sein de la Leiden Collection.
Le notebook sert de support du dialogue entre plusieurs disciplines,
ici, l’histoire, la géographie et l’ingénierie des connaissances. Le
notebook est aussi le lieu d’un processus collaboratif productif de
connaissances (synchrone ou asynchrone), devient un outil pédagogique -
par la formation par la recherche grâce à sa transformation en fiche
rzine et est susceptible de servir de méthodologie (ou “fil
directeur”) reproductible d’un processus similaire pour d’autres
problématiques.
Bibliographie
Annexes
Info session
| setting | value |
|---|---|
| version | R version 4.3.0 (2023-04-21) |
| os | Ubuntu 22.04.2 LTS |
| system | x86_64, linux-gnu |
| ui | X11 |
| language | (EN) |
| collate | fr_FR.UTF-8 |
| ctype | fr_FR.UTF-8 |
| tz | Europe/Paris |
| date | 2023-06-07 |
| pandoc | 2.19.2 @ /usr/lib/rstudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown) |
| package | ondiskversion | source |
|---|---|---|
| dplyr | 1.1.2 | CRAN (R 4.3.0) |
| DT | 0.27 | CRAN (R 4.3.0) |
| ggplot2 | 3.4.2 | CRAN (R 4.3.0) |
| glitter | 0.1.0 | https://lvaudor.r-universe.dev (R 4.3.0) |
| jpeg | 0.1.10 | CRAN (R 4.3.0) |
| mapview | 2.11.0 | CRAN (R 4.3.0) |
| patchwork | 1.1.2 | CRAN (R 4.3.0) |
| rnaturalearth | 0.3.2 | CRAN (R 4.3.0) |
| sf | 1.0.12 | CRAN (R 4.3.0) |
| tmap | 3.3.3 | CRAN (R 4.3.0) |
| WikidataQueryServiceR | 1.0.0 | CRAN (R 4.3.0) |
| WikidataR | 2.3.3 | CRAN (R 4.3.0) |
Citation
KRUMMEICH R, PECOUT H, REY-COYREHOURCQ S (2022). “Spatio-temporal, Wikidata, exploration de données collaboratives du web 3.0.”, doi:10.48645/xxxxxx https://doi.org/10.48645/xxxxxx,, https://rzine.fr/publication_rzine/xxxxxxx/.
BibTex :
@Misc{,
title = {Spatio-temporal Wikidata, exploration de données collaboratives du web 3.0},
subtitle = {Histoire de cadre : élaboration d’une trajectoire spatio-temporelle},
author = {Raphaëlle KRUMMEICH and Hugues PECOUT and Sébastien REY-COYREHOURCQ},
doi = {10.48645/xxxxxx},
url = {https://rzine.fr/publication_rzine/xxxxxxx/},
keywords = {FOS: Other social sciences},
language = {fr},
publisher = {FR2007 CIST},
year = {2022},
copyright = {Creative Commons Attribution Share Alike 4.0 International},
}
Glossaire
DBpedia est une ontologie permettant de traduire Wikipedia en dépôts de données définis dans le cadre de description des ressources du standard Ressources Description Framework (RDF) du World Wide Web Consortium1 (W3C)↩︎
Le Web de données (linked data, en anglais) est une initiative du W3C (Consortium World Wide Web) visant à favoriser la publication de données structurées sur le Web, non pas sous la forme de silos de données isolés les uns des autres, mais en les reliant entre elles pour constituer un réseau global d’informations.↩︎
Un triplet est un groupe formé par trois éléments dont chacun appartient à un ensemble distinct.↩︎
Un URI (Uniform Resource Identifier, en français Identifiant unique de ressource) est une chaîne qui fait référence à une ressource. Les plus courantes sont les URL, qui identifient une ressource en donnant son emplacement sur le Web. Au contraire, les URN font référence à une ressource grâce à son nom, dans un environnement donné, par exemple le code ISBN d’un livre.↩︎
acronyme récursif qui signifie SPARQL Protocol And RDF Query Language (Wikipédia (2022)). Plusieurs langages de requête destinés à interroger les graphes RDF ont été développés, mais le langage SPARQL est développé par le W3C de sorte à devenir un standard.↩︎
Un préfixe est une modalité de simplification d’écriture faisant référence à un espace de noms, voir notamment, les préfixes Wikidata↩︎
Le géoréférencement est l’un des principes fondamentaux des systèmes d’information géographiques (SIG) et de la cartographie assistée par ordinateur (CAO). Un objet géographiques est référencé lorsque l’on lui attribut une localisation (coordonnées géographiques) et une forme (géométrie : point, ligne ou surface).↩︎
Le format Well-known text, abrégé en WKT, peut se traduire par « texte bien lisible ». C’est un format standard en mode texte utilisé pour représenter des objets géométriques vectoriels issus des systèmes d’informations géographiques (SIG), mais aussi des informations s’y rattachant, tels les références de systèmes de coordonnées.↩︎
Un système de coordonnées est un référentiel dans lequel on peut représenter des éléments dans l’espace. Ce système permet de se situer sur l’ensemble du globe terrestre grâce à un couple de coordonnées géographiques.↩︎